#include "EPSG/MouseManipulator.h"

#include "EPSG/Camera.h"

#include <math.h>

/* System Includes */
#ifdef WIN32
#include <Windows.h>
#endif

/* OpenGL Includes */
#include <GL/GL.h>


EPSG::MouseManipulator::MouseManipulator( EPSG::Camera* camera )
: EPSG::Manipulator( camera )
{

}

bool EPSG::MouseManipulator::apply( int button, int state, int x, int y )
{
	if( _camera == NULL )
		return false;

	if( state == 0 )
	{
		_button = button;
		_x0 = x;
		_y0 = y;
	}
	else
	{
		_button = -1;
	}
	return false;
}

bool EPSG::MouseManipulator::apply( int x, int y )
{
	if( _button < 0 )
	{
		return false;
	}

	int dx = abs(x - _x0);
	int dy = abs(y - _y0);

	if( _button == 0 ) // Left mouse button
	{
		Vec3<float> v0 = map( _x0, _y0 );
		Vec3<float> v1 = map( x, y );
		Vec3<float> r = Vec3<float>::cross( v0, v1 );
		_camera->rotate( ( 2*asin( r.length() ) * 180.0f/PI ) / 10, r.x, r.y, r.z );
		_x0 = x;
		_y0 = y;
		return true;
	}
	else if( _button == 1 ) // Middle mouse button
	{
		int vp[4];
		glGetIntegerv( GL_VIEWPORT, vp );
		float f;
		if( dx > dy )
			f = (float)(x - _x0) / vp[2];
		else
			f = (float)(-y + _y0) / vp[3];

		_camera->translate( 0, f * 5, 0 );
		return true;
	}
	else if( _button == 2 ) // Right mouse button
	{
		int vp[4];
		glGetIntegerv( GL_VIEWPORT, vp );
		float f;
		if( dx > dy )
			f = (float)(x - _x0) / vp[2];
		else
			f = (float)(-y + _y0) / vp[3];

		_camera->translate( 0, 0, f * 5 );
		return true;
	}

	return false;
}

EPSG::Vec3<float> EPSG::MouseManipulator::map( int x, int y )
{
	Vec3<float> v;
	int vp[4];
	glGetIntegerv( GL_VIEWPORT,vp );
	int radius = vp[2] < vp[3] ? vp[2]/2 : vp[3]/2;
	v.x = (float)( ( x-vp[0] ) - vp[2]/2 ) / radius;
	v.y = (float)( ( vp[3]-y-vp[0] ) - vp[3]/2 ) / radius;
	float len = sqrt( v.x*v.x + v.y*v.y );
	if( len > 1.0 )
	{
		v.x /= len;
		v.y /= len;
		v.z = 0.0f;
	}
	else
	{
		v.z = sqrt(1 - v.x*v.x - v.y*v.y);
	}
	return v;
}